/**
 * 版权所有(C)，上海勾芒信息科技，2016，所有权利保留。
 * 
 * 项目名：	total-core
 * 文件名：	QueryDecoderSupport.java
 * 模块说明：	
 * 修改历史：
 * 2016年7月4日 - Debenson - 创建。
 */
package com.thor.palmmall.dao.common;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.core.convert.converter.Converter;

import com.thor.commons.query.QueryCondition;
import com.thor.commons.query.QueryOrder;
import com.thor.commons.query.SQLSubquery;
import com.thor.commons.query2.QueryConditionDecoder2;
import com.thor.commons.query2.QueryOrderDecoder2;
import com.thor.commons.util.Assert;
import com.thor.commons.util.StringUtil;

/**
 * @author Debenson
 * @since 0.1
 */
public abstract class QueryDecoderSupport implements QueryConditionDecoder2, QueryOrderDecoder2 {

  /**
   * 构造日期介于起止时间段的查询条件。
   * 
   * @param condition
   * @param sql
   * @param fieldName
   * @return
   */
  protected void appendDateFieldBetween(QueryCondition condition, SQLSubquery sql,
      String fieldName) {
    appendDateFieldBetween(condition, sql, fieldName, Format.fmt_yMdHms);
  }

  /**
   * 构造日期介于起止时间段的查询条件。
   * 
   * @param condition
   * @param sql
   * @param fieldName
   * @param dateFormat
   * @return
   */
  protected void appendDateFieldBetween(QueryCondition condition, SQLSubquery sql, String fieldName,
      final FastDateFormat dateFormat) {
    Assert.assertArgumentNotNull(sql, "sql");
    Assert.assertArgumentNotNull(condition, "condition");
    Assert.assertArgumentNotNull(fieldName, "fieldName");
    Assert.assertArgumentNotNull(dateFormat, "dateFormat");

    appendValueFieldBetween(condition, sql, fieldName, new Converter<Object, Date>() {

      @Override
      public Date convert(Object source) {
        if (source instanceof Date) {
          return (Date) source;
        } else if (source instanceof Number) {
          return new Date(((Number) source).longValue());
        } else if (source instanceof String) {
          if (StringUtil.isNullOrBlank(((String) source))) {
            return null;
          } else {
            try {
              return (Date) dateFormat.parseObject(((String) source));
            } catch (ParseException e) {
              return null;
            }
          }
        } else {
          return null;
        }
      }

    });
  }

  /**
   * 构造Integer介于起止范围内的查询条件。
   * 
   * @param condition
   * @param sql
   * @param fieldName
   * @return
   */
  protected void appendIntegerFieldBetween(QueryCondition condition, SQLSubquery sql,
      String fieldName) {
    appendValueFieldBetween(condition, sql, fieldName, new Converter<Object, Integer>() {

      @Override
      public Integer convert(Object source) {
        if (source instanceof Integer) {
          return (Integer) source;
        } else if (source instanceof String) {
          if (StringUtil.isNullOrBlank(((String) source))) {
            return null;
          } else {
            return Integer.valueOf((String) source);
          }
        } else {
          return null;
        }
      }

    });
  }

  /**
   * 构造BigDecimal介于起止范围内的查询条件。
   * 
   * @param condition
   * @param sql
   * @param fieldName
   * @return
   */
  protected void appendBigDecimalFieldBetween(QueryCondition condition, SQLSubquery sql,
      String fieldName) {
    appendValueFieldBetween(condition, sql, fieldName, new Converter<Object, BigDecimal>() {

      @Override
      public BigDecimal convert(Object source) {
        if (source instanceof Double) {
          return BigDecimal.valueOf(((Double) source).doubleValue());
        } else if (source instanceof BigDecimal) {
          return (BigDecimal) source;
        } else if (source instanceof String) {
          if (StringUtil.isNullOrBlank(((String) source))) {
            return null;
          } else {
            return new BigDecimal((String) source);
          }
        } else {
          return null;
        }
      }

    });
  }

  /**
   * 构造BigDecimal介于起止范围内的查询条件。
   * 
   * @param condition
   * @param sql
   * @param fieldName
   * @param converter
   * @return
   */
  @SuppressWarnings({
      "unchecked", "rawtypes" })
  protected void appendValueFieldBetween(QueryCondition condition, SQLSubquery sql,
      String fieldName, Converter converter) {
    Assert.assertArgumentNotNull(condition, "condition");
    Assert.assertArgumentNotNull(sql, "sql");
    Assert.assertArgumentNotNull(fieldName, "fieldName");
    Assert.assertArgumentNotNull(converter, "converter");

    // 查询字段
    final String operation = condition.getOperation();

    List<Object> values = condition.getParameters();
    if (values.size() <= 0) {
      throw new IllegalArgumentException(MessageFormat.format("参数“{0}”非法", operation));
    }

    if (values.size() > 0 && values.get(0) != null) {
      final Object beginValue = converter.convert(values.get(0));
      sql.appendConditionEx(fieldName + " >= :begin_" + fieldName.replaceAll("\\.", ""),
          beginValue);
    }

    if (values.size() > 1 && values.get(1) != null) {
      final Object endValue = converter.convert(values.get(1));
      sql.appendConditionEx(fieldName + " <= :end_" + fieldName.replaceAll("\\.", ""), endValue);
    }
  }

  /** 排序条件: 创建人名称 */
  protected static final String ORDER_BY_CREATE_NAME = "createName";
  /** 排序条件: 创建时间 */
  protected static final String ORDER_BY_CREATE_TIME = "createTime";
  /** 排序条件: 最后修改时间 */
  protected static final String ORDER_BY_LAST_MODIFIED_TIME = "lastModifiedTime";

  @Override
  public void decodeOrder(QueryOrder order, SQLSubquery sql) {
    if (ORDER_BY_CREATE_NAME.equals(order.getField())) {
      sql.appendOrder("o.createInfo.operator.operName", order.getDirection());

    } else if (ORDER_BY_CREATE_TIME.equals(order.getField())) {
      sql.appendOrder("o.createInfo.time", order.getDirection());

    } else if (ORDER_BY_LAST_MODIFIED_TIME.equals(order.getField())) {
      sql.appendOrder("o.lastModifyInfo.time", order.getDirection());
    }
  }

  /** 创建人名称类似于 */
  protected static final String CONDITION_CREATE_NAME_LEKE = "createNameLike";
  /** 单据创建时间介于 */
  protected static final String CONDITION_CREATE_TIME_BETWEEN = "createTimeBetween";
  /** 最后修改时间介于 */
  protected static final String CONDITION_LAST_MODIFIED_TIME = "lastModifiedTimeBetween";

  @Override
  public void decodeCondition(QueryCondition condition, SQLSubquery sql) {
    final String operation = condition.getOperation();
    final Object parameter = condition.getParameter();

    if (CONDITION_CREATE_NAME_LEKE.equals(operation)) {
      sql.appendConditionEx("o.createInfo.operator.operName like :name", "%" + parameter + "%");

    } else if (CONDITION_CREATE_TIME_BETWEEN.equals(operation)) {
      appendDateFieldBetween(condition, sql, "o.createInfo.time");

    } else if (CONDITION_LAST_MODIFIED_TIME.equals(operation)) {
      appendDateFieldBetween(condition, sql, "o.lastModifyInfo.time");

    }
  }

}
